#include "cimport.h"
#include <string>
#include <iostream>
#include <fstream>
#include "cimport.h"
#include "..\math\matrix.h"
#include "..\math\functions.h"

using namespace std;

namespace NEngine {

// ================================================================================================
// Iterate the file until we build all the data
// ================================================================================================
int CImportObject::IterateFile(fstream& object, uint& curoffset) {
    // -- see if we are in the right part of the file
    string meshobj;
    object >> meshobj;
    if(meshobj.compare("Mesh:"))
        return true;
    
    // -- temporary index holder
    CDynamicArray<ushort> tempidx;

    // -- get shapename
    string shapename;
    object >> shapename;
    objects.names.Append(shapename);

    // -- get vertices
    string vectortitle;
    uint numverts;
    CDynamicArray<Vector4> tverts;
    object >> vectortitle >> numverts;
    Vector4 verts;
    for(uint i = 0; i < numverts; ++i) {
        object >> verts.x;
        object >> verts.y;
        object >> verts.z;
        tverts.Append(verts);
    }

    // -- get verts per face
    string vertsper;
    uint numfaces;
    object >> vertsper >> numfaces;
    ushort vertsperface;
    CDynamicArray<uint> vertsperfaces;
    for(uint i = 0; i < numfaces; ++i) {
        object >> vertsperface;
        vertsperfaces.Append(vertsperface);
    }

    // -- get indices
    string index;
    uint numindices;
    object >> index >> numindices;
    ushort indice;
    for(uint i = 0; i < numindices; ++i) {
        object >> indice;
        tempidx.Append(indice);
    }

    string wmatrix;
    Matrix4x4 mat;
    object >> wmatrix;
    object >> mat.m[0][0] >> mat.m[0][1] >> mat.m[0][2] >> mat.m[0][3];
    object >> mat.m[1][0] >> mat.m[1][1] >> mat.m[1][2] >> mat.m[1][3];
    object >> mat.m[2][0] >> mat.m[2][1] >> mat.m[2][2] >> mat.m[2][3];
    object >> mat.m[3][0] >> mat.m[3][1] >> mat.m[3][2] >> mat.m[3][3];
    objects.wmats.Append(mat);

    // -- grow a list of vertice fan
    uint indxstart = 0;
    numindices = 0;
    for(uint i = 0; i < numfaces; ++i) {
        for(uint j = 1; j < (vertsperfaces[i]-1); ++j){
            objects.indices.Append(tempidx[indxstart]);
            objects.indices.Append(tempidx[indxstart+j]);
            objects.indices.Append(tempidx[indxstart+(j+1)]);
            numindices += 3;
        }
        indxstart += vertsperfaces[i];
    }

    objects.numindices.Append(numindices);

    uint j = 0;
    for(uint i = curoffset; i < objects.indices.GetSize(); i += 3) {
        Vector4 v0 = tverts[objects.indices[i]];
        Vector4 v1 = tverts[objects.indices[i+1]];
        Vector4 v2 = tverts[objects.indices[i+2]];

        Vector4 ab = v1 - v0;
        Vector4 ac = v2 - v0;
        Vector4 norm = Normalize(CrossProduct(ab, ac));

        objects.vertices.Append(v0);
        objects.vertices.Append(v1);
        objects.vertices.Append(v2);
        objects.normals.Append(norm);
        objects.normals.Append(norm);
        objects.normals.Append(norm);

        j += 3;
    }

    objects.numverts.Append(j);

    // -- create the color vertices
    for(uint i = 0; i < j; ++i) {
        if(i % 3 == 0)
            objects.colors.Append(Vector4(0.0f, 0.0f, 1.0f));
        if(i % 3 == 1)
            objects.colors.Append(Vector4(1.0f, 0.0f, 0.0f));
        if(i % 3 == 2)
            objects.colors.Append(Vector4(0.0f, 1.0f, 0.0f));
    } 


    curoffset += numindices;
    return object.eof();
}

// ================================================================================================
// Import object information from a file
// ================================================================================================
void CImportObject::Import() {
    // -- open file
    fstream object;
    ASSERT_(files.GetSize() != 0, "No files to import");
    
    for(uint i = 0; i < files.GetSize(); ++i) {
        object.open(files[i], ios::in);

    	// -- check for file failure
    	if(object.fail()) {
    	    cout << "File " << files[i].c_str() << " failed to load.\n";
    	    cout << "Exiting application.";
    	    exit(-1);
    	}

    	built = true;
    	uint curoffset = 0;
    	while(!IterateFile(object, curoffset)) {
    	    // -- iterate the file
    	}
    }
}

// ================================================================================================
// Iterate the file for light objects
// ================================================================================================
int CImportLights::IterateFile(std::fstream& file) {
    // -- see if we are in the right part of the file
    string lightobject;
    file >> lightobject;
    if(!lightobject.compare("DirLight:")) {
	    // -- get shapename
	    string shapename;
	    file >> shapename;
	    lobjects.dirnames.Append(shapename);

        // -- get the intensity
        string intense;
        float intensity;
        file >> intense;
        file >> intensity;
        lobjects.dirintenses.Append(intensity);

        // -- get the color
        string color;
        Vector4 clr;
        file >> color;
        file >> clr.x;
        file >> clr.y;
        file >> clr.z;
        file >> clr.w;
        lobjects.dirclrs.Append(clr);

        // -- get the transformation
	    string wmatrix;
	    Matrix4x4 mat;
	    file >> wmatrix;
	    file >> mat.m[0][0] >> mat.m[0][1] >> mat.m[0][2] >> mat.m[0][3];
	    file >> mat.m[1][0] >> mat.m[1][1] >> mat.m[1][2] >> mat.m[1][3];
	    file >> mat.m[2][0] >> mat.m[2][1] >> mat.m[2][2] >> mat.m[2][3];
	    file >> mat.m[3][0] >> mat.m[3][1] >> mat.m[3][2] >> mat.m[3][3];
	    lobjects.dirlights.Append(mat);

	    lobjects.numdirlights += 1;
    }
    else if(!lightobject.compare("PointLight:")) {
        // --  get shapename
        string shapename;
        file >> shapename;
        lobjects.ptnames.Append(shapename);

        // -- get the intensity
        string intense;
        float intensity;
        file >> intense;
        file >> intensity;
        lobjects.ptintenses.Append(intensity);

        // -- get the color
        string color;
        Vector4 clr;
        file >> color;
        file >> clr.x;
        file >> clr.y;
        file >> clr.z;
        file >> clr.w;
        lobjects.ptclrs.Append(clr);

        // -- get the transformation
        string wmatrix;
	    Matrix4x4 mat;
	    file >> wmatrix;
	    file >> mat.m[0][0] >> mat.m[0][1] >> mat.m[0][2] >> mat.m[0][3];
	    file >> mat.m[1][0] >> mat.m[1][1] >> mat.m[1][2] >> mat.m[1][3];
	    file >> mat.m[2][0] >> mat.m[2][1] >> mat.m[2][2] >> mat.m[2][3];
	    file >> mat.m[3][0] >> mat.m[3][1] >> mat.m[3][2] >> mat.m[3][3];
        lobjects.ptlights.Append(mat);
        
        lobjects.numptlights += 1; 
    }
    else if(!lightobject.compare("SpotLight:")) {
        // --  get shapename
        string shapename;
        file >> shapename;
        lobjects.sptnames.Append(shapename);

        // -- get the intensity
        string intense;
        float intensity;
        file >> intense;
        file >> intensity;
        lobjects.sptintenses.Append(intensity);

        // -- get the umbra
        string umbra;
        float umbraangle;
        file >> umbra;
        file >> umbraangle;
        lobjects.sptumbras.Append(umbraangle);

        // -- get the penumbra
        string penum;
        float penumangle;
        file >> penum;
        file >> penumangle;
        lobjects.sptpenums.Append(penumangle);

        // -- get the color
        string color;
        Vector4 clr;
        file >> color;
        file >> clr.x;
        file >> clr.y;
        file >> clr.z;
        file >> clr.w;
        lobjects.sptclrs.Append(clr);

        // -- get the transformation
        string orientation;
        Vector4 rotation;
        Vector4 position;
        file >> orientation;
        file >> rotation.x >> rotation.y >> rotation.z; 
        rotation.w = 1.0f;
        file >> position.x >> position.y >> position.z;
        position.w = 1.0f;
        lobjects.sptlightsor.Append(rotation);
        lobjects.sptlightspos.Append(position);
        lobjects.numsptlights += 1; 
    }

    return file.eof();
}

// ================================================================================================
// Import light object information from a file
// ================================================================================================
void CImportLights::Import() {
    // -- open file
    fstream fobject;
    ASSERT_(files.GetSize() != 0, "No files to import");

    for(uint i = 0; i < files.GetSize(); ++i) {
        fobject.open(files[i], ios::in);

    	// -- check for file failure
    	if(fobject.fail()) {
    	    cout << "File " << files[i].c_str() << " failed to load.\n";
    	    cout << "Exiting application.";
    	    exit(-1);
    	}

    	built = true;
    	uint curoffset = 0;
    	lobjects.numdirlights = 0;
    	lobjects.numptlights = 0;
    	lobjects.numsptlights = 0;
    	while(!IterateFile(fobject)) {
    	    // -- iterate the file
    	}
    }
}

} // namespace NEngine
